package com.zz.server.handle.defaults;

import com.zz.common.annotation.Executor;
import com.zz.common.config.Constants;
import com.zz.common.entity.Information;
import com.zz.common.entity.Meta;
import com.zz.common.entity.ProtocolInfo;
import com.zz.common.enums.MessageType;
import com.zz.common.enums.SerializationType;
import com.zz.common.handle.executor.AbstractMessageExecutor;
import com.zz.common.protocol.DefaultProtocol;
import com.zz.common.utils.ObjectUtil;
import com.zz.common.utils.SnowflakeUtil;
import com.zz.server.config.ChannelCache;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.internal.EmptyArrays;
import lombok.extern.slf4j.Slf4j;

import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

/**
 * 断开连接
 */
@Slf4j
@Executor(msgType = MessageType.TYPE_DISCONNECT)
public class DisconnectedExecutor extends AbstractMessageExecutor {
    @Override
    public void execute(Information information) {
        ChannelHandlerContext context = information.getContext();
        DefaultProtocol protocol = (DefaultProtocol) information.getProtocolMsg();
        Meta meta = protocol.getMeta();
        if (ObjectUtil.isNull(meta)) {
            log.error("client disconnect error, meta is null");
            return;
        }
        String domain = meta.getConfig().getDomain();
        if (ObjectUtil.isEmpty(domain)) {
            log.error("client disconnect error, domain is null");
            return;
        }
        Channel masterServerChannel = ChannelCache.getChannelByDomain(domain);
        if (ObjectUtil.isNull(masterServerChannel)) {
            log.error("client disconnect error, masterServerChannel is null");
            return;
        }
        Map<String, Channel> channelCache = masterServerChannel.attr(Constants.Attributes.CHANNEL_CACHE).get();
        if (ObjectUtil.isNull(channelCache) || channelCache.isEmpty() || !channelCache.containsKey(meta.getLocalChannelId())) {
            log.error("client disconnect error, localChannel is null");
            return;
        }
        Channel localChannel = channelCache.get(meta.getLocalChannelId());
        localChannel.attr(Constants.Attributes.SERVER_CHANNEL).set(Constants.Objects.CHANNEL_NULL);
        context.channel().attr(Constants.Attributes.LOCAL_CHANNEL).set(Constants.Objects.CHANNEL_NULL);
        channelCache.remove(meta.getLocalChannelId());
        localChannel.writeAndFlush(EmptyArrays.EMPTY_BYTES).addListener(ChannelFutureListener.CLOSE);
    }

    @Override
    public void execute(ProtocolInfo protocolInfo) {
        Channel serverChannel = protocolInfo.getServerChannel();
        // 构建连接消息
        DefaultProtocol protocolMsg = DefaultProtocol.builder().type(protocolInfo.getType())
                .serialNumber(SnowflakeUtil.genSnowflakeId())
                .serializationType(SerializationType.PROTOSTUFF)
                .build();
        serverChannel.writeAndFlush(protocolMsg);
    }
}
